package com.seed.application.context;

import com.seed.application.context.impl.DevSeedContext;
import com.seed.core.query.App;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;

import static java.nio.file.StandardWatchEventKinds.*;

/*
    监控指定目录（包含子文件夹）下文件的创建、删除和修改
 */
@Slf4j
public class SeedWatcher {
    private final WatchService service;
    private final Path rootDir;
    private final DevSeedContext seedContext;

    public SeedWatcher(DevSeedContext seedContext) throws IOException {
        this.seedContext = seedContext;
        this.service = FileSystems.getDefault().newWatchService();
        this.rootDir = Paths.get(seedContext.getPath().getAbsolutePath());

        // 递归注册所有子目录
        register(this.rootDir);
    }

    private void register(final Path start) throws IOException {
        Files.walk(start).filter(Files::isDirectory).forEach(subDir -> {
            try {
                subDir.register(service, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
            } catch (IOException e) {
                System.err.println("无法注册目录 " + subDir + ": " + e);
            }
        });
    }

    public void start() {
        while (true) {
            WatchKey key;
            try {
                key = service.take();
            } catch (InterruptedException e) {
                System.err.println("监控被中断");
                return;
            }

            for (WatchEvent<?> event : key.pollEvents()) {
                WatchEvent.Kind<?> kind = event.kind();

                if (kind == OVERFLOW) continue;

                @SuppressWarnings("unchecked")
                WatchEvent<Path> ev = (WatchEvent<Path>) event;
                Path filename = ev.context();

                Path dir = (Path) key.watchable();
                Path fullPath = dir.resolve(filename);
                boolean isDirectory = Files.isDirectory(fullPath);
                if(!isDirectory) {
                    String fileName = fullPath.toString().substring(rootDir.toString().length() + 1);
                    int pos = fileName.indexOf(File.separator);
                    String owner = null;
                    String appName;
                    if(pos == -1) {
                        appName = fileName.substring(0, fileName.indexOf('.'));
                    } else {
                        owner = fileName.substring(0, pos);
                        appName = fileName.substring(pos + 1, fileName.indexOf('.'));
                    }
                    reload(owner, appName);
                }

                // 如果是新建目录，则注册监控
                if (kind == ENTRY_CREATE && isDirectory) {
                    try {
                        register(fullPath);
                    } catch (IOException e) {
                        System.err.println("无法注册新目录 " + fullPath + ": " + e);
                    }
                }
            }

            key.reset();
        }
    }

    public void reload(String owner, String appName) {
        App app = seedContext.getApp(owner, appName);
        if(app != null) {
            log.info("重新载入owner={}, appName={}", owner, appName);
            seedContext.reloadApp(owner, appName);
        }
    }

//    public static void reload(String owner, String appName) {
//        App app = A.getApp(owner, appName);
//        if(app != null) {
//            log.info("重新载入owner={}, appName={}", owner, appName);
//            A.reloadApp(owner, appName);
//            App app1 = A.getApp(owner, appName);
//            System.out.println(JSONUtil.toJsonStr(app1));
//        }
//    }

//    public static void watch(String path) {
//        Path dir = Paths.get(path);
//        try {
//            new SeedWatcher(dir).start();
//            System.out.printf("开始监控目录【%s】", path);
//        } catch (IOException e) {
//            System.err.println("开启监控失败:" + e.getMessage());
//        }
//    }
}
